View Javadoc

1   /*
2    * Copyright (C) 1998-2000 Semiotek Inc.  All Rights Reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted under the terms of either of the following
6    * Open Source licenses:
7    *
8    * The GNU General Public License, version 2, or any later version, as
9    * published by the Free Software Foundation
10   * (http://www.fsf.org/copyleft/gpl.html);
11   *
12   *  or
13   *
14   * The Semiotek Public License (http://webmacro.org/LICENSE.)
15   *
16   * This software is provided "as is", with NO WARRANTY, not even the
17   * implied warranties of fitness to purpose, or merchantability. You
18   * assume all risks and liabilities associated with its use.
19   *
20   * See www.webmacro.org for more information on the WebMacro project.
21   */
22  
23  package org.webmacro.util;
24  
25  import org.webmacro.*;
26  
27  import java.io.UnsupportedEncodingException;
28  import java.util.HashMap;
29  import java.util.Map;
30  
31  /***
32   * A provider which dispenses Encoders, which are used for encoding
33   * Strings and caching the results.
34   * @since 0.96
35   * @author Michael Bayne
36   */
37  
38  public class EncoderProvider implements Provider
39  {
40  
41      private Map _encoders = new HashMap();
42      private Broker _broker;
43      private Settings _config;
44  
45      /***
46       * The provider type for this provider. Use this when calling
47       * <code>Broker.getProvider()</code>.
48       */
49      public static final String TYPE = "encoder";
50  
51      /***
52       * Return an array representing the types this provider serves up
53       */
54      public String getType ()
55      {
56          return TYPE;
57      }
58  
59      /***
60       * Initialize this provider based on the specified config. Derived
61       * encoder provider implementations may override this method to obtain
62       * initialization parameters of their own devising, but they must be
63       * sure to call super.init() in their overridden methods.
64       */
65      public void init (Broker b, Settings config) throws InitException
66      {
67          _broker = b;
68          _config = config;
69      }
70  
71      // Implementation note: the flush(), destroy() and get() methods are
72      // instance synchronized to ensure that if _encoders is cleared via the
73      // destroy() method and get() is called subsequently, we properly avoid
74      // referencing the null variable. We can't synchronize on _encoders
75      // because that becomes null and code that does this:
76      //
77      // if (_encoders != null) {
78      //    synchronized (_encoders) {
79      //
80      // is not valid because the _encoders reference could become null
81      // in between those two statements.
82      //
83      // Additionally, the EncoderProvider is not invoked frequently enough
84      // to merit a more sophisticated synchronization approach (it is only
85      // called once per request when creating a FastWriter with which to
86      // output the response and not even that often because FastWriter
87      // instances are cached). Thus, we choose simplicity and robustness in
88      // this situation.
89  
90      /***
91       * Clear any cache this provider may be maintaining.
92       */
93      public synchronized void flush ()
94      {
95          // clean out the encoder cache
96          _encoders.clear();
97      }
98  
99      /***
100      * Close down this provider, freeing any allocated resources.
101      */
102     public synchronized void destroy ()
103     {
104         // clear out our reference to the encoder cache to allow it to be
105         // garbage collected
106         _encoders = null;
107     }
108 
109     /***
110      * Get the object associated with the specified query.
111      */
112     public synchronized Object get (String encoding) throws ResourceException
113     {
114         Encoder encoder = null;
115 
116         // make sure we're not inadvertently being called after we've
117         // already been destroy()ed
118         if (_encoders != null)
119         {
120             encoder = (Encoder) _encoders.get(encoding);
121 
122             if (encoder == null)
123             {
124                 try
125                 {
126                     // create and cache a new encoder instance for this
127                     // encoding if one doesn't already exist in the cache
128                     encoder = new Encoder(encoding);
129                     encoder.init(_broker, _config);
130                     _encoders.put(encoding, encoder);
131                 }
132                 catch (InitException e)
133                 {
134                     throw new ResourceException("Unable to initialize Encoder for "
135                             + encoding + "; " + e);
136                 }
137                 catch (UnsupportedEncodingException uee)
138                 {
139                     throw new NotFoundException("Unsupported encoding: " +
140                             uee.getMessage());
141                 }
142             }
143         }
144         return encoder;
145     }
146 }